--- /dev/null
+# Copyright (C) 2011,2012 Colin Walters <walters@verbum.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+# ostbuild-compile-one-make wraps systems that implement the GNOME build API:
+# http://people.gnome.org/~walters/docs/build-api.txt
+
+import os,sys,stat,subprocess,tempfile,re,shutil
+import argparse
+from StringIO import StringIO
+import json
+
+from . import builtins
+from .ostbuildlog import log, fatal
+from . import vcs
+from .subprocess_helpers import run_sync, run_sync_get_output
+from . import buildutil
+
+class OstbuildSourceDiff(builtins.Builtin):
+ name = "source-diff"
+ short_description = "Show differences in source code between builds"
+
+ def __init__(self):
+ builtins.Builtin.__init__(self)
+
+ def _snapshot_from_rev(self, rev):
+ self.init_repo()
+ text = run_sync_get_output(['ostree', '--repo=' + self.repo,
+ 'cat', rev, '/contents.json'],
+ log_initiation=False)
+ return json.loads(text)
+
+ def execute(self, argv):
+ parser = argparse.ArgumentParser(description=self.short_description)
+ parser.add_argument('--rev-from')
+ parser.add_argument('--rev-to')
+ parser.add_argument('--snapshot-from')
+ parser.add_argument('--snapshot-to')
+
+ args = parser.parse_args(argv)
+ self.parse_config()
+
+ to_snap = None
+ from_snap = None
+
+ if args.rev_to:
+ to_snap = self._snapshot_from_rev(args.rev_to)
+ if args.rev_from:
+ from_snap = self._snapshot_from_rev(args.rev_from)
+ if args.snapshot_from:
+ from_snap = json.load(open(args.snapshot_from))
+ if args.snapshot_to:
+ to_snap = json.load(open(args.snapshot_to))
+
+ if to_snap is None:
+ fatal("One of --rev-to/--snapshot-to must be given")
+ if from_snap is None:
+ if args.rev_to:
+ from_snap = self._snapshot_from_rev(args.rev_to + '^')
+ else:
+ fatal("One of --rev-from/--snapshot-from must be given")
+
+ diff_replace_re = re.compile(' [ab]')
+
+ for from_component in from_snap['components']:
+ name = from_component['name']
+ src = from_component['src']
+ (keytype, uri) = vcs.parse_src_key(src)
+ if keytype == 'local':
+ log("Component %r has local URI" % (name, ))
+ continue
+ mirrordir = vcs.ensure_vcs_mirror(self.mirrordir, keytype, uri, from_component['branch'])
+
+ to_component = self.find_component_in_snapshot(name, to_snap)
+ if to_component is None:
+ log("DELETED COMPONENT: %s" % (name, ))
+ continue
+
+ from_revision = from_component.get('revision')
+ to_revision = to_component.get('revision')
+ if from_revision is None:
+ log("From component %s missing revision" % (name, ))
+ continue
+ if to_revision is None:
+ log("From component %s missing revision" % (name, ))
+ continue
+
+ if from_revision != to_revision:
+ env = dict(os.environ)
+ env['LANG'] = 'C'
+
+ spacename = ' ' + name
+
+ proc = subprocess.Popen(['git', 'diff', from_revision, to_revision],
+ env=env, cwd=mirrordir, stdout=subprocess.PIPE)
+ for line in proc.stdout:
+ if (line.startswith('diff --git ')
+ or line.startswith('--- a/')
+ or line.startswith('+++ b/')
+ or line.startswith('Binary files /dev/null and b/')):
+ line = diff_replace_re.sub(spacename, line)
+ sys.stdout.write(line)
+ else:
+ sys.stdout.write(line)
+ proc.wait()
+
+builtins.register(OstbuildSourceDiff)
meta['config-opts'] = config_opts
return meta
- def get_component(self, name):
- assert self.snapshot is not None
- for component in self.snapshot['components']:
+ def find_component_in_snapshot(self, name, snapshot):
+ for component in snapshot['components']:
if component['name'] == name:
return component
- fatal("Couldn't find component '%s' in manifest" % (component_name, ))
+ return None
+
+ def get_component(self, name, in_snapshot=None):
+ if in_snapshot is None:
+ assert self.snapshot is not None
+ target_snapshot = self.snapshot
+ else:
+ target_snapshot = in_snapshot
+ component = self.find_component_in_snapshot(self, target_snapshot)
+ if component is None:
+ fatal("Couldn't find component '%s' in manifest" % (component_name, ))
+ return component
def get_expanded_component(self, name):
return self.expand_component(self.get_component(name))
self._bin_snapshots = self.create_db('bin-snapshot')
return self._bin_snapshots
- def _init_repo(self):
+ def init_repo(self):
+ if self.repo is not None:
+ return self.repo
repo = ostbuildrc.get_key('repo', default=None)
if repo is not None:
self.repo = repo
def parse_snapshot(self, prefix, path):
self.parse_prefix(prefix)
- self._init_repo()
+ self.init_repo()
if path is None:
latest_path = self.get_src_snapshot_db().get_latest_path()
if latest_path is None: